package com.geqian.web.authentication.filter;

import com.geqian.cache.cache.SimpleCacheTemplate;
import com.geqian.web.authentication.LoginUserDetails;
import com.geqian.web.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Component
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private final List<String> permitURIList = new ArrayList<>();

    @Resource
    private SimpleCacheTemplate<String, Object> simpleCacheTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        String token;
        if (isWebSocketRequest(request)) {
            //获取token
            token = request.getHeader("Sec-WebSocket-Protocol");
        } else {
            //获取token
            token = request.getHeader("token");
            if (token == null || token.isEmpty() || matching(request.getRequestURI())) {
                filterChain.doFilter(request, response);
                return;
            }
        }

        //解析token
        String userId = JwtUtils.parseForValue(token, "userId", String.class);

        //从redis中获取用户信息
        LoginUserDetails loginUserDetails = (LoginUserDetails) simpleCacheTemplate.get("user:" + userId);
        if (Objects.isNull(loginUserDetails)) {
            throw new RuntimeException("用户未登录");
        }
        //获取用户信息，存入SecurityContextHolder中
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUserDetails, null, loginUserDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        // FilterChain放行
        filterChain.doFilter(request, response);
    }


    @Autowired
    private void setPermitURI(Environment environment) {
        String contextPath = environment.getProperty("server.servlet.context-path");
        String loginUri = environment.getProperty("application.login.uri");
        String registerUri = environment.getProperty("application.register.uri");
        permitURIList.add(contextPath == null ? loginUri : contextPath + loginUri);
        permitURIList.add(contextPath == null ? registerUri : contextPath + registerUri);
        permitURIList.add(contextPath == null ? "/user/getVerificationCode" : contextPath + "/user/getVerificationCode");
    }


    /**
     * 匹配URI
     *
     * @param uri
     * @return
     */
    private boolean matching(String uri) {
        return permitURIList.stream().anyMatch(regex -> uri.matches(regex));
    }


    /**
     * 判断是否是 WebSocket 请求
     *
     * @param request
     * @return
     */
    private boolean isWebSocketRequest(HttpServletRequest request) {
        String connection = request.getHeader("Connection");
        String upgrade = request.getHeader("Upgrade");
        return "upgrade".equalsIgnoreCase(connection) && "websocket".equalsIgnoreCase(upgrade);
    }
}